// Copyright (c) 2021 Presto Labs Pte. Ltd.
// Author: daniel

#include "coin2/exchange/bitbank/api_order/native_rest_async_asio_subscriber.h"

#include <glog/logging.h>

#include "coin2/base/time.h"
#include "coin2/exchange/bitbank/api_order/native_private_client.h"
#include "coin2/exchange/order/bitbank.pb.h"

namespace coin2::exchange::bitbank::api_order {

void BitbankRestAsyncAsioSubscriber::QueryBalance() {
  auto http_context = rest_client()->QueryAccountBalance();
  if (!http_context) {
    return;
  }
  http_context->handler =
      std::bind(&BitbankRestAsyncAsioSubscriber::HandleQuery, this, std::placeholders::_1);
  http_driver_->PostAsyncContext(http_context);
}

void BitbankRestAsyncAsioSubscriber::QueryOpenOrders(const std::string& native_symbol) {
  RestParams params;
  params.set_pair(native_symbol);
  auto http_context = rest_client()->QueryOrders(params);
  if (!http_context) {
    return;
  }
  http_context->handler =
      std::bind(&BitbankRestAsyncAsioSubscriber::HandleQuery, this, std::placeholders::_1);
  http_driver_->PostAsyncContext(http_context);
}

/*
void BitbankRestAsyncAsioSubscriber::QueryOrderInfo() {
  if (query_orders_info_in_process_) {
    return;
  }
  query_orders_info_in_process_ = true;
  RestParams params;
  auto open_orders = order_mgr_->GetOpenOrdersCopy();
  for (auto& order : open_orders) {
    params.set_pair(order.second);
    params.set_order_id(order.first);
    auto http_context = rest_client()->QueryOrderInfo(params);
    if (!http_context) {
      continue;
    }
    http_context->handler = std::bind(
        &BitbankRestAsyncAsioSubscriber::HandleQuery,
        this,
        std::placeholders::_1);
    http_driver_->PostAsyncContext(http_context);
  }
  query_orders_info_in_process_ = false;
}
*/

void BitbankRestAsyncAsioSubscriber::QueryOrdersInfo(const std::string& native_symbol) {
  if (query_orders_info_in_process_) {
    return;
  }
  auto open_orders = order_mgr_->GetOpenOrdersCopyBySymbol(native_symbol);
  if (open_orders.size() == 0) {
    return;
  }
  query_orders_info_in_process_ = true;
  RestParams params;
  params.set_pair(native_symbol);
  auto beg = open_orders.begin();
  auto end = open_orders.end();
  while (beg != end) {
    params.add_order_ids(beg->first);
    if (params.order_ids_size() >= 30) {  // maximum number of order id is 30
      auto http_context = rest_client()->QueryOrdersInfo(params);
      if (http_context) {
        http_context->handler =
            std::bind(&BitbankRestAsyncAsioSubscriber::HandleQuery, this, std::placeholders::_1);
        http_driver_->PostAsyncContext(http_context);
      }
      params.mutable_order_ids()->Clear();
    }
    beg = open_orders.erase(beg);
  }
  if (params.order_ids_size() > 0) {
    auto http_context = rest_client()->QueryOrdersInfo(params);
    if (http_context) {
      http_context->handler =
          std::bind(&BitbankRestAsyncAsioSubscriber::HandleQuery, this, std::placeholders::_1);
      http_driver_->PostAsyncContext(http_context);
    }
  }
  query_orders_info_in_process_ = false;
}

void BitbankRestAsyncAsioSubscriber::QueryFills(const std::string& native_symbol) {
  RestParams params;
  params.set_pair(native_symbol);
  auto http_context = rest_client()->QueryTrades(params);
  if (!http_context) {
    return;
  }
  http_context->handler =
      std::bind(&BitbankRestAsyncAsioSubscriber::HandleQuery, this, std::placeholders::_1);
  http_driver_->PostAsyncContext(http_context);
}

void BitbankRestAsyncAsioSubscriber::SubscribeAsync() {
  AddPeriodicTask(
      std::bind(&BitbankRestAsyncAsioSubscriber::QueryBalance, this),
      config_.query_account_balance_period_sec(),
      "query_balance");

  const auto symbol_list = native_symbols();

  AddPeriodicTask(
      std::bind(&BitbankRestAsyncAsioSubscriber::QueryOpenOrders, this, std::placeholders::_1),
      config_.query_open_orders_period_sec(),
      "query_open_orders",
      symbol_list);

  AddPeriodicTask(
      std::bind(&BitbankRestAsyncAsioSubscriber::QueryFills, this, std::placeholders::_1),
      config_.query_fill_period_sec(),
      "query_fills",
      symbol_list);

  AddPeriodicTask(
      std::bind(&BitbankRestAsyncAsioSubscriber::QueryOrdersInfo, this, std::placeholders::_1),
      config_.query_cancel_orders_period_sec(),
      "query_orders_info",
      symbol_list);
}

}  // namespace coin2::exchange::bitbank::api_order
